package org.karelun.gef.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.ui.views.properties.ColorPropertyDescriptor;
import org.eclipse.ui.views.properties.IPropertyDescriptor;
import org.eclipse.ui.views.properties.IPropertySource;
import org.eclipse.ui.views.properties.PropertyDescriptor;
import org.eclipse.ui.views.properties.TextPropertyDescriptor;
import org.karelun.gef.helper.ConstantMessages;
import org.karelun.gef.helper.IDConstant;
import org.karelun.gef.property.ConstraintPropertySource;
import org.karelun.gef.property.FontPropertyDescriptor;
import org.karelun.gef.property.PropertyLabelProvider;
import org.karelun.gef.utils.FontDataUtils;
import org.karelun.gef.utils.NodeUtils;

public abstract class Node extends Element implements IPropertySource,
/* Cloneable, */Serializable {

	private static final long serialVersionUID = 1L;

	protected String text = null;

	private Point location = null;

	private Dimension size = null;

	private String id = null;

	private RGB foreColor = null;

	private RGB bgColor = null;

	private FontData fontData;

	private DiagramModel diagram;

	private List<AbstractConnectionModel> sourceConnection = null;

	private List<AbstractConnectionModel> targetConnection = null;

	public Node() {
		super();
	}

	public void setText(String text) {
		if (text == null)
			return;
		if (this.text != null && this.text.equals(text))
			return;
		this.text = text;
		firePropertyChange(NodeConstants.PROP_TEXT, null, text);
	}

	public void setLocation(int x, int y) {
		Point point = new Point(x, y);
		setLocation(point);
	}

	public void setLocation(Point p) {
		if (p == null)
			return;
		if (location != null && location.equals(p)) {
			return;
		}
		if (NodeUtils.isOverlap(this, p, getSize()))
			return;
		location = p;
		firePropertyChange(NodeConstants.PROP_LOCATION, null, p);
	}

	public void setSize(int width, int height) {
		Dimension d = new Dimension(width, height);
		setSize(d);
	}

	public void setSize(Dimension d) {
		if (d == null)
			return;
		if (size != null && size.equals(d)) {
			return;
		}
		if (NodeUtils.isOverlap(this, getLocation(), d))
			return;
		this.size = d;
		firePropertyChange(NodeConstants.PROP_SIZE, null, d);
	}

	public void setId(String id) {
		if (id == null)
			return;
		if (this.id != null && this.id.equals(id))
			return;
		this.id = id;
	}

	public void setForeColor(RGB foreColor) {
		if (foreColor == null)
			return;
		if (this.foreColor != null && this.foreColor.equals(foreColor))
			return;
		this.foreColor = foreColor;
		firePropertyChange(NodeConstants.PROP_FORE_COLOR, null, foreColor);
	}

	public void setBgColor(RGB bgColor) {
		if (bgColor == null)
			return;
		if (this.bgColor != null && this.bgColor.equals(bgColor))
			return;
		this.bgColor = bgColor;
		firePropertyChange(NodeConstants.PROP_BG_CLOR, null, bgColor);
	}

	public void setFontData(FontData fontData) {
		if (fontData == null)
			return;
		if (this.fontData != null && this.fontData.equals(fontData))
			return;
		this.fontData = fontData;
		firePropertyChange(NodeConstants.PROP_FONT, null, fontData);
	}

	public void setDiagram(DiagramModel diagram) {
		this.diagram = diagram;
	}

	public String getText() {
		return text;
	}

	public Point getLocation() {
		return location;
	}

	public Dimension getSize() {
		return size;
	}

	public String getId() {
		return id;
	}

	public RGB getForeColor() {
		return foreColor;
	}

	public RGB getBgColor() {
		return bgColor;
	}

	public FontData getFontData() {
		return fontData;
	}

	public DiagramModel getDiagram() {
		return diagram;
	}

	public void addtargetConnection(AbstractConnectionModel connection) {
		if (targetConnection == null)
			targetConnection = new ArrayList<AbstractConnectionModel>();
		targetConnection.add(connection);
		firePropertyChange(NodeConstants.PROP_TARGET, null, null);
	}

	public void addsourceConnection(AbstractConnectionModel connection) {
		if (sourceConnection == null)
			sourceConnection = new ArrayList<AbstractConnectionModel>();
		sourceConnection.add(connection);
		firePropertyChange(NodeConstants.PROP_SOURCE, null, null);
	}

	public List<AbstractConnectionModel> getModelTargetConnection() {
		return this.targetConnection;
	}

	public List<AbstractConnectionModel> getModelSourceConnection() {
		return this.sourceConnection;
	}

	public void removeTargetConnection(Object connection) {
		this.targetConnection.remove(connection);
		firePropertyChange(NodeConstants.PROP_TARGET, null, null);
	}

	public void removeSourceConnection(Object connection) {
		this.sourceConnection.remove(connection);
		firePropertyChange(NodeConstants.PROP_SOURCE, null, null);
	}

	public Object getEditableValue() {
		return this;
	}

	public IPropertyDescriptor[] getPropertyDescriptors() {
		TextPropertyDescriptor nameDescriptor = new TextPropertyDescriptor(
				NodeConstants.PROP_TEXT, ConstantMessages.property_Name);
		nameDescriptor.setLabelProvider(new PropertyLabelProvider(
				IDConstant.Name_prop));
		PropertyDescriptor constraintDesc = new PropertyDescriptor(
				NodeConstants.PROP_CONSTRAINT, ConstantMessages.property_Dimen);
		ColorPropertyDescriptor foreColorPropDesc = new ColorPropertyDescriptor(
				NodeConstants.PROP_FORE_COLOR,
				ConstantMessages.ForeColor_Property);
		ColorPropertyDescriptor bgColorDesc = new ColorPropertyDescriptor(
				NodeConstants.PROP_BG_CLOR,
				ConstantMessages.BackGroundColor_Property);
		FontPropertyDescriptor fontDesc = new FontPropertyDescriptor(
				NodeConstants.PROP_FONT, ConstantMessages.Font_Property);

		IPropertyDescriptor[] descriptor = new IPropertyDescriptor[] {
				nameDescriptor, constraintDesc, foreColorPropDesc, bgColorDesc,
				fontDesc };
		return descriptor;
	}

	public Object getPropertyValue(Object id) {
		if (NodeConstants.PROP_TEXT.equals(id))
			return getText();
		if (NodeConstants.PROP_CONSTRAINT.equals(id)) {
			// Rectangle rect = new Rectangle(getLocation().x, getLocation().y,
			// getSize().width, getSize().height);
			Rectangle rect = new Rectangle(1, 1, 1, 1);
			return new ConstraintPropertySource(rect);
		} else if (NodeConstants.PROP_FORE_COLOR.equals(id)) {
			return getForeColor();
		} else if (NodeConstants.PROP_BG_CLOR.equals(id)) {
			return getBgColor();
		} else if (NodeConstants.PROP_FONT.equals(id)) {
			return getFontData();
		}
		return null;
	}

	public boolean isPropertySet(Object id) {
		if (NodeConstants.PROP_TEXT.equals(id)
				|| NodeConstants.PROP_CONSTRAINT.equals(id))
			return true;
		return false;
	}

	public void resetPropertyValue(Object id) {

	}

	public void setPropertyValue(Object id, Object value) {
		if (NodeConstants.PROP_TEXT.equals(id)) {
			String text = (String) value;
			setText(text);
		}
		if (NodeConstants.PROP_CONSTRAINT.equals(id)) {
			Rectangle rect = (Rectangle) value;
			Point loc = rect.getLocation();
			setLocation(loc);
			Dimension size = rect.getSize();
			setSize(size);
		} else if (NodeConstants.PROP_FORE_COLOR.equals(id)) {
			setForeColor((RGB) value);
		} else if (NodeConstants.PROP_BG_CLOR.equals(id)) {
			setBgColor((RGB) value);
		} else if (NodeConstants.PROP_FONT.equals(id)) {
			FontData data = (FontData) value;
			setFontData(data);
			Dimension newSize = FontDataUtils.getFontSize(getText(), data);
			setSize(newSize);
		}
	}

	public Object clone() {
		try {
			return super.clone();
		} catch (CloneNotSupportedException e) {
		}
		return null;
	}
}